package com.sky.module.suppot.datatrace.util;


import com.sky.module.suppot.datatrace.annotation.HistoryRecord;

import java.lang.reflect.Field;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 工具类：比较两个对象并获取其中不相等的字段
 * 需要配合@ChangeLogDes注解进行使用
 * 使用@ChangeLogDesc注解标注相应字段来设置属性的描述信息
 * 只有使用@ChangeLogDesc注解标注的属性才会生成ChangeLog
 */
public abstract class AbstractContrast<T extends BaseChangeLog> {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    /**
     * 比较两个对象属性o1和o2是否相等 相等返回true(子类根据实际情况重写对比方法)
     *
     * @param o1
     * @param o2
     * @return
     */
    protected boolean isEquals(Object o1, Object o2) {
        return Objects.deepEquals(o1, o2);
    }

    /**
     * 初始化变更记录对象(需要子类根据实际情况重写)
     *
     * @return
     */
    protected abstract T initChangeLog();

    /**
     * 比较两个对象并获取其中不相等的字段
     *
     * @param obj1 对象1
     * @param obj2 对象2
     * @return
     */
    public List<T> compareFields(Object obj1, Object obj2) {
        try {
            List<T> changeLogList = new LinkedList<>();
            //只有两个对象都是同一类型才有可比性
            if (obj1.getClass() != obj2.getClass()) {
                return changeLogList;
            }
            List<Field> fieldList = new ArrayList<>();
            Class tempClass = obj1.getClass();
            // 相当于递归获取到所有的属性 获取到所有父类
            while (tempClass != null) {//当父类为null的时候说明到达了最上层的父类(Object类).
                fieldList.addAll(Arrays.asList(tempClass.getDeclaredFields()));
                tempClass = tempClass.getSuperclass(); //得到父类,然后赋给自己
            }

            for (Field field : fieldList) {
                //设置对象的访问权限，保证对private的属性的访问
                field.setAccessible(true);
                //只有使用@ChangeLogDesc注解标注的属性才会生成ChangeLog
                HistoryRecord annotation = field.getAnnotation(HistoryRecord.class);
                if (annotation == null) {
                    continue;
                }
                String propName = field.getName();
                //获取obj1、obj2的属性值
                Object o1 = field.get(obj1);
                Object o2 = field.get(obj2);
                //时间格式转换
                if (o1 instanceof ZonedDateTime) {
                    o1 = ((ZonedDateTime) o1).format(formatter);
                }
                if (o2 instanceof ZonedDateTime) {
                    o2 = ((ZonedDateTime) o2).format(formatter);
                }
                //如果不相等构建ChangeLog放入集合中
                if (!isEquals(o1, o2)) {
                    //初始化ChangeLog
                    T changeLog = initChangeLog();
                    //属性名
                    changeLog.setPropName(propName);
                    //属性描述
                    changeLog.setPropDesc(annotation.field());
                    //变更前
                    changeLog.setBeforeChange(o1 != null ? String.valueOf(o1) : "");
                    //变更后
                    changeLog.setAfterChange(o2 != null ? String.valueOf(o2) : "");
                    changeLogList.add(changeLog);
                }
            }
            return changeLogList;
        } catch (Exception e) {
            throw new RuntimeException("比对过程中发生异常", e);
        }
    }
}
